package com.tanhua.app.service;

import cn.hutool.core.collection.CollUtil;
import com.tanhua.api.MovementApi;
import com.tanhua.api.UserInfoApi;
import com.tanhua.api.VisitorsApi;
import com.tanhua.app.exception.BusinessException;
import com.tanhua.app.intercept.UserHolder;
import com.tanhua.commons.utils.Constants;
import com.tanhua.config.template.OssTemplate;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.pojo.UserInfo;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.MovementsVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VisitorsVo;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class MovementService {

    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private MovementApi movementApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private VisitorsApi visitorsApi;

    @Autowired
    private StringRedisTemplate redisTemplate;


    /**
     * 实现发布动态逻辑
     *
     * @param movement
     * @param imageContent
     */
    public void publishMovement(Movement movement, MultipartFile[] imageContent) throws IOException {
        //1.判断用户发布的动态是否含有文本内容
        if (StringUtils.isEmpty(movement.getTextContent())) {
            //不存在,则抛出异常
            throw new BusinessException(ErrorResult.contentError());
        }

        //2.获取当前用户的id
        Long userId = UserHolder.getUserId();
        //3.将动态内容中的图片上传到阿里云OSS
        //3.1创建一个集合存储图片的访问路径（动态的图片内容可能不止一个）
        List<String> imageUrls = new ArrayList<>();
        //3.2遍历imageContent，上传内容
        for (MultipartFile multipartFile : imageContent) {
            String imageUrl = ossTemplate.upload(multipartFile.getInputStream(), multipartFile.getOriginalFilename());
            imageUrls.add(imageUrl);
        }

        //4.将数据封装成对象
        movement.setUserId(userId);
        movement.setMedias(imageUrls);

        //5.调用api发布动态(注入依赖)
        movementApi.save(movement);
    }


    /**
     * 根据用户id查询用户动态（我的动态）
     *
     * @param userId
     * @param page
     * @param pagesize
     * @return
     */
    public PageResult<MovementsVo> findByUserIdMovement(Long userId, Integer page, Integer pagesize) {
        //1.判断UserId是否为空，为空则用当前用户的id
        if (userId == null) {
            userId = UserHolder.getUserId();
        }

        //2.根据用户id查询该用户的动态
        PageResult<Movement> movementsVoPageResult = movementApi.findByUserIdMovement(userId, page, pagesize);

        //3.判断查询的动态数据是否为空
        if (movementsVoPageResult.getItems() == null || movementsVoPageResult.getItems().isEmpty()) {
            //直接返回
            return new PageResult<>(movementsVoPageResult.getPage(), movementsVoPageResult.getPage(), 0, null);
        }

        //3.根据用户id查询用户详情
        UserInfo userInfo = userInfoApi.findById(userId);

        //4.获取用户的动态数据
        List<Movement> movementList = movementsVoPageResult.getItems();

        //5.创建MovementVo封装对象
        List<MovementsVo> movementsVos = new ArrayList<>();

        //6.遍历用户的动态数据集合
        for (Movement movement : movementList) {
            MovementsVo movementsVo = MovementsVo.init(userInfo, movement);
            movementsVos.add(movementsVo);
        }

        //7.返回结果
        return new PageResult<>(movementsVoPageResult.getPage(), movementsVoPageResult.getPagesize(), movementsVoPageResult.getCounts(), movementsVos);

    }


    /**
     * 查询好友动态(分页展示)
     *
     * @param page
     * @param pagesize
     * @return
     */
    public PageResult<MovementsVo> findFriendMovements(Integer page, Integer pagesize) {
        //1.获取当前登录用户的id
        Long userId = UserHolder.getUserId();

        //2.根据登录用户的Id，分页查询好友发布的动态
        List<Movement> movementList = movementApi.findFriendMovements(userId, page, pagesize);

        return getMovementsVoPageResult(page, pagesize, movementList);
    }


    /**
     * 抽取公共方法:封装动态Vo对象
     *
     * @param page
     * @param pagesize
     * @param movementList
     * @return
     */
    private PageResult<MovementsVo> getMovementsVoPageResult(Integer page, Integer pagesize, List<Movement> movementList) {
        //3.判断查询的好友动态集合是否为空
        if (movementList == null || movementList.isEmpty()) {
            //为空直接返回
            return new PageResult<>(page, pagesize, 0, null);
        }

        //4.获取发布动态好友的id(因为前端页面不只是需要好友发布动态的数据信息movement，还需要好友的详情userInfo)
        List<Long> ids = movementList.stream().map(Movement::getUserId).collect(Collectors.toList());

        //5.根据好友id查询好友的详情
        List<UserInfo> userInfoList = userInfoApi.findFriendIds(ids);

        //6.将查询到的好友详情集合转为map集合，方便提取
        Map<Long, UserInfo> userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserInfo::getId, Function.identity()));

        //7.创建vo对象，用来返回
        //创建vo对象
        List<MovementsVo> movementsVos = new ArrayList<>();
        //遍历集合查询到的好友动态集合，并将每一个好友的动态和自身的详情信息封装为Vo对象
        for (Movement movement : movementList) {
            //获取好友的详情信息
            UserInfo userInfo = userInfoMap.get(movement.getUserId());
            //判断好友信息是否存在
            if (userInfo != null) {
                MovementsVo movementsVo = MovementsVo.init(userInfo, movement);

                //识别点赞标识
                String likeKey = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
                String likeHasKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
                if (redisTemplate.opsForHash().hasKey(likeKey,likeHasKey)){
                    movementsVo.setHasLiked(1);
                }else {
                    movementsVo.setHasLiked(0);
                }

                //识别喜欢标识
                String loveKey = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
                String loveHasKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
                if (redisTemplate.opsForHash().hasKey(loveKey,loveHasKey)){
                    movementsVo.setHasLoved(1);
                }else {
                    movementsVo.setHasLoved(0);
                }


                movementsVos.add(movementsVo);
            }
        }

        //8.返回结果
        return new PageResult<>(page, pagesize, 0, movementsVos);
    }


    /**
     * 查询推荐好友动态
     *
     * @param page
     * @param page
     * @return
     */
    public PageResult findRecommendMovements(Integer page, Integer pagesize) {
        //1.从redis缓存中获取推荐数
        String redisKey = Constants.MOVEMENTS_RECOMMEND + UserHolder.getUserId();
        String redisValue = redisTemplate.opsForValue().get(redisKey);

        //2.判断缓存中的数据是否存在
        List<Movement> movementList = new ArrayList<>();
        if (StringUtils.isEmpty(redisValue)) {
            //2.1 如果不存在推荐动态数据，随机获取10条动态数据
            movementList = movementApi.randomMovements();
        } else {
            String[] pidArr = redisValue.split(",");
            //2.2 如果存在，判断当前的动态数据是否可以进行分页
            if (pidArr.length > (page - 1) * pagesize) {
                //如果可以分页，要进行分页处理  获取pid
                List<Long> pidList = Arrays.stream(pidArr)  //把数组转为流进行处理
                        .skip((page - 1) * pagesize)
                        .limit(pagesize)
                        .map(pid -> Long.parseLong(pid))  //把String转为Long
                        .collect(Collectors.toList());   //最终返回的是List

                //根据获取的id查询推荐的动态数据
                movementList = movementApi.findByPids(pidList);
            }
        }

        //3.调用封装Vo对象方法，封装vo对象，并返回
        return getMovementsVoPageResult(page, pagesize, movementList);
    }


    /**
     * 根据动态id查询该动态的详情（动态详情和用户详情）
     *
     * @param movementId
     * @return
     */
    public MovementsVo findMovementByMovementId(String movementId) {
        //1.调用动态Id查询动态详情
        Movement movement = movementApi.findMovementByMovementId(movementId);

        //2.获取用户id,查询该动态用户的详情
        UserInfo userInfo = userInfoApi.findById(UserHolder.getUserId());

        //3.封装成Vo对象
        //判断查询的动态是否为空
        if (movement != null){
            MovementsVo movementsVo = MovementsVo.init(userInfo, movement);
            return movementsVo;
        }else {
            return null;
        }
    }

    /**
     * 谁看过我
     * @return
     */
    public List<VisitorsVo> queryVisitorsList() {
        //1.构建查询条件，查询访问时间
        String key = Constants.VISITORS_USER;
        String hasKey = String.valueOf(UserHolder.getUserId());
        String date = (String) redisTemplate.opsForHash().get(key, hasKey);

        //2.根据当前用户id和查询时间进行查询
        List<Visitors> visitorsList = visitorsApi.queryVisitorsList(date, UserHolder.getUserId());
        if (CollUtil.isEmpty(visitorsList)){
            return new ArrayList<>();
        }
        //3.获取访客的id,在根据访客id查询访客的用户详情
        List<Long> idsList = visitorsList.stream().map(Visitors::getVisitorUserId).collect(Collectors.toList());
        List<UserInfo> userInfoList = userInfoApi.findByUserIds(idsList,null);

        //4.将查询到的用户详情集合转换成map集合
        Map<Long, UserInfo> map = userInfoList.stream().collect(Collectors.toMap(UserInfo::getId, Function.identity()));

        //5.封装vo对象
        List<VisitorsVo> visitorsVoList = new ArrayList<>();
        for (Visitors visitors : visitorsList) {
            UserInfo userInfo = map.get(visitors.getVisitorUserId());
            if (userInfo != null){
                VisitorsVo visitorsVo = VisitorsVo.init(userInfo, visitors);
                visitorsVoList.add(visitorsVo);
            }
        }
        return visitorsVoList;
    }
}
